----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    17:34:32 10/05/2013 
-- Design Name: 
-- Module Name:    multiplier_noCycle - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
library UNISIM;
use UNISIM.VComponents.all;

entity multiplier_noCycle is
    Port ( clk : in STD_LOGIC;
			  a : in  STD_LOGIC_VECTOR (31 downto 0);
           b : in  STD_LOGIC_VECTOR (31 downto 0);
           output : out  STD_LOGIC_VECTOR (63 downto 0));
end multiplier_noCycle;

architecture Behavioral of multiplier_noCycle is
	component MULT18X18
		port ( P : out STD_LOGIC_VECTOR (35 downto 0);
				 A : in STD_LOGIC_VECTOR (17 downto 0);
				 B : in STD_LOGIC_VECTOR (17 downto 0));
	end component;
	
--	signal outLL : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
--	signal outLH : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
--	signal outHL : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
--	signal outHH : STD_LOGIC_VECTOR (69 downto 0) := (others => '0');
--	signal aHigher : STD_LOGIC_VECTOR (17 downto 0) := (others => '0');
--	signal bHigher : STD_LOGIC_VECTOR (17 downto 0) := (others => '0');
--	signal aLower : STD_LOGIC_VECTOR (17 downto 0) := (others => '0');
--	signal bLower : STD_LOGIC_VECTOR (17 downto 0) := (others => '0');
	
	signal outLL : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
	signal outLH : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
	signal outHL : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
	signal outHH : STD_LOGIC_VECTOR (69 downto 0) := (others => '0');
	signal aHigher : STD_LOGIC_VECTOR (15 downto 0) := (others => '0');
	signal bHigher : STD_LOGIC_VECTOR (15 downto 0) := (others => '0');
	signal aLower : STD_LOGIC_VECTOR (15 downto 0) := (others => '0');
	signal bLower : STD_LOGIC_VECTOR (15 downto 0) := (others => '0');
	
	signal l2Sum : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
	signal l2Carry : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
begin
--	EMBED_MULTIPLIER_LL : MULT18X18 port map (P => outLL (35 downto 0),
--															A => aLower,
--															B => bLower);
--															
--	EMBED_MULTIPLIER_LH : MULT18X18 port map (P => outLH (52 downto 17),
--															A => aLower,
--															B => bHigher);
--															
--	EMBED_MULTIPLIER_HL : MULT18X18 port map (P => outHL (52 downto 17),
--															A => aHigher,
--															B => bLower);
--															
--	EMBED_MULTIPLIER_HH : MULT18X18 port map (P => outHH (69 downto 34),
--															A => aHigher,
--															B => bHigher);

--		aHigher <= "000" & a (31 downto 17);
--		bHigher <= "000" & b (31 downto 17);
--		aLower  <= '0' & a (16 downto 0);
--		bLower  <= '0' & b (16 downto 0);
		
		aHigher <= a (31 downto 16);
		bHigher <=  b (31 downto 16);
		aLower  <= a (15 downto 0);
		bLower  <=  b (15 downto 0);
		
		outLL (31 downto 0) <= aLower * bLower;
		outLH (47 downto 16) <= aLower * bHigher;
		outHL (47 downto 16) <= aHigher * bLower;
		outHH (63 downto 32) <= aHigher * bHigher;
		
process(clk)
	variable l1Sum : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
	variable l1Carry : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
	--variable l2Sum : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
	--variable l2Carry : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
	variable l1CarryUp : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
	variable l2CarryUp : STD_LOGIC_VECTOR (63 downto 0) := (others => '0');
begin
	if clk = '1' and clk'event then
		l1Sum := (outLL xor outLH) xor outHL;
		l1Carry := (outLL and outLH) or (outLL and outHL) or (outLH and outHL);
		l1CarryUp := l1Carry(62 downto 0) & '0';
		
		l2Sum <= (l1Sum xor l1CarryUp) xor (outHH(63 downto 0));
		l2Carry <= (l1Sum and l1CarryUp) or (l1Sum and (outHH(63 downto 0))) or (l1CarryUp and (outHH(63 downto 0)));
		--l2Sum := (l1Sum xor l1CarryUp) xor (outHH(63 downto 0));
		--l2Carry := (l1Sum and l1CarryUp) or (l1Sum and (outHH(63 downto 0))) or (l1CarryUp and (outHH(63 downto 0)));
		l2CarryUp := l2Carry(62 downto 0) & '0';
		
		output <= l2Sum + l2CarryUp;
	end if;
end process;
end Behavioral;
